package cn.edu.sgu.www.mhxysy.util;

import cn.edu.sgu.www.mhxysy.config.property.UploadsProperties;
import cn.edu.sgu.www.mhxysy.exception.GlobalException;
import cn.edu.sgu.www.mhxysy.restful.ResponseCode;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletRequest;
import java.io.File;
import java.io.IOException;
import java.util.List;

/**
 * 文件上传工具类
 * @author 沐雨橙风ιε
 * @version 1.0
 */
@Slf4j
@Component
public class UploadUtils {

    /**
     * 应用名
     */
    @Value("${spring.application.name}")
    private String name;

    /**
     * 文件上传根路径
     */
    private final String root;

    /**
     * 文件上传临时目录
     */
    private final String tempDir;

    /**
     * 图片文件名后缀（文件类型）
     */
    private final List<String> fileTypes;

    /**
     * 小写字母
     */
    private static final String LOWER_LETTERS;

    static {
        StringBuilder sb = new StringBuilder();

        for (int i = 97; i < 122; i++) {
            char letter = (char) i;

            sb.append(letter);
        }

        LOWER_LETTERS = sb.toString();
    }

    @Autowired
    public UploadUtils(UploadsProperties uploadsProperties) {
        this.root = uploadsProperties.getPath();
        this.tempDir = uploadsProperties.getTempDir();
        this.fileTypes = uploadsProperties.getFileTypes();
    }

    public String getRoot() {
        return root;
    }

    /**
     * 图片上传
     * @param file MultipartFile对象
     * @param directory 文件上传目录
     * @return String 图片的相对路径
     */
    public String upload(MultipartFile file, String directory) throws IOException {
        boolean result = checkFileType(file);

        if (result) {
            // 创建临时目录
            File tempDirctory = new File(tempDir + "/" + name + directory);

            if (!tempDirctory.exists()) {
                tempDirctory.mkdirs();
            }

            // 得到请求参数中的数据ID
            HttpServletRequest request = HttpUtils.getRequest();

            String id = request.getParameter("id");

            // 获取原始文件名
            String originalFilename = file.getOriginalFilename();

            // 设置保存的文件名
            String fileName = getBase(directory.charAt(1)) + Integer.parseInt(id) + StringUtils.getFileType(originalFilename);

            // 保存文件到临时目录
            File targetFile = new File(tempDirctory, fileName);

            file.transferTo(targetFile);

            // 拼接并返回文件名（解决图片缓存问题）
            return directory + "/" + fileName + "?timestamp=" + System.currentTimeMillis();
        }

        return null;
    }

    /**
     * 检查文件格式
     * @param file MultipartFile
     */
    private boolean checkFileType(MultipartFile file) {
        if (file == null) {
            throw new GlobalException(ResponseCode.BAD_REQUEST, "您未上传任何图片！");
        }

        String filename = file.getOriginalFilename();

        if (StringUtils.isNullOrEmpty(filename)) {
            throw new GlobalException(ResponseCode.BAD_REQUEST, "获取上传的文件名失败~");
        }

        // 通过文件名获取文件类型
        String fileType = StringUtils.getFileType(filename);

        // 文件类型未定义
        if (!fileTypes.contains(fileType)) {
            throw new GlobalException(ResponseCode.BAD_REQUEST, "只允许上传格式为" + fileTypes + "的图片");
        }

        return true;
    }

    /**
     * 获取基数
     * @param c 字母
     * @return int
     */
    public static int getBase(char c) {
        // 得到首字母的下标
        int base = LOWER_LETTERS.indexOf(c);

        base ++; // 数组下标从0开始
        base %= 10;

        // 防止base模运算后变成0，文件名只有一位数
        if (base == 0) {
            base = 1;
        }

        base *= 1000;

        return base;
    }

    /**
     * 移动文件
     * @param fileName 文件名
     * @return String 新的文件名
     */
    public boolean moveFile(String fileName) {
        // 创建临时目录和目标目录
        File tempFile = new File(tempDir + "/" + name, fileName);
        File targetFile = new File(root, fileName);

        // 文件存在才删除
        if (targetFile.exists() && targetFile.isFile()) {
            // 删除原来的文件
            if (targetFile.delete()) {
                // 删除成功
                log.debug("成功删除原来的文件：{}", targetFile.getPath());
            }
        }

        // 文件重命名
        boolean renameTo = tempFile.renameTo(targetFile);

        if (renameTo) {
            log.debug("文件移动成功：{} ==> {}", tempFile.getPath(), targetFile.getPath());
        }

        return renameTo;
    }

}